/****************************************************************************
 *  Copyright: National ICT Australia,  2007 - 2010                         *
 *  Developed at the ATP lab, Networked Systems research theme              *
 *  Author(s): Athanassios Boulis, Yuriy Tselishchev                        *
 *  This file is distributed under the terms in the attached LICENSE file.  *
 *  If you do not find this file, copies can be found by writing to:        *
 *                                                                          *
 *      NICTA, Locked Bag 9013, Alexandria, NSW 1435, Australia             *
 *      Attention:  License Inquiry.                                        *
 *                                                                          *
 ****************************************************************************/

#ifndef TUNABLEMACRLMODULE
#define TUNABLEMACRLMODULE
/*******RL************/
#include <map>
#include <vector>
#include <queue>
#include "ResourceManager.h"
/*********************/

#include "VirtualMac.h"
#include "TunableMacRLControl_m.h"
#include "TunableMacRLPacket_m.h"
/*****************************************************************************************/
#define TX_TIME(x) (phyLayerOverhead + x)*1/(1000*phyDataRate/8.0)	//x are in BYTES
/*****************************************************************************************/
using namespace std;

enum backoffTypes {
	BACKOFF_SLEEP_INT = 2200,
	BACKOFF_CONSTANT = 2201,
	BACKOFF_MULTIPLYING = 2202,
	BACKOFF_EXPONENTIAL = 2203
};

enum MacStates {
	MAC_STATE_DEFAULT = 1,
	MAC_STATE_TX = 2,
	MAC_STATE_CONTENDING = 3,
	MAC_STATE_RX = 4
};

enum TunableMacTimers {
	START_SLEEPING = 1,
	START_LISTENING = 2,
	START_CARRIER_SENSING = 3,
	ATTEMPT_TX = 4,
	SEND_BEACONS_OR_DATA = 5,
	
/******* RL TIMER ***********/
	//~ SYN_FORWARD = 6,
	START_LEARNING = 7,
	FRAME_RL = 8,
	SLOT_RL = 9,
	EE_RL = 10,
/***************************/

};

/******************************* RL STRUCT **********************************************/
struct neighborRecord {
	unsigned int nodeID;
	float EE;
	unsigned int temp;   // inserito solo per evitare problemi di overflow della struttura
	//~ int timesRx;
	//~ int receivedPackets;
};

struct pktTime {
	TunableMacRLPacket *pktB;
	double timestamp;
};

/*********************************************************************************************/


class TunableMACRL: public VirtualMac {
 private:
	/*--- The .ned file's parameters ---*/
	double dutyCycle;		// sleeping interval / sleeping + listening intervals
	double listenInterval;	// in secs, note: parammeter in omnetpp.ini in msecs
	double beaconIntervalFraction;
	double probTx;			// probability of a single transmission to happen
	int numTx;				// when we have something to send, how many times do we try to transmit it.
							// We say "try" because probTx might be < 1
	double randomTxOffset;	// when have somethingnto transmit, don't do it immediatelly
	double reTxInterval;	// the interval between retransmissions, in msec but after a
							// time [0..randomTxOffset] chosen randomly (uniform)
	int beaconFrameSize;	// in bytes
	int backoffType;		// can be 0 or 1 or 2 or 3
	double backoffBaseValue;// the backoff value
	double CSMApersistance; // value in [0..1], is CSMA non-persistent, p-persistent, or 1-persistent
	bool txAllPacketsInFreeChannel; // when channel free, tx all packets in buffer?
	bool sleepDuringBackoff;	// for no dutyCycle case: sleep when backing off?

	int phyLayerOverhead;
	simtime_t phyDelayForValidCS;	// delay for valid CS
	double phyDataRate;

	int macState;
	int numTxTries;
	int backoffTimes;	// number of consequtive backoff times
	int remainingBeaconsToTx;
	double beaconTxTime;	// time it takes to TX a beacon in secs
	double sleepInterval;	// in secs
	
/***************************************************************** RL VARIABLES ************************************/

/******** RL Parameters (see ned file) ********/

	bool activeLearning;
	double startLearningTime;

	double frameLenght;
	unsigned int frameWindow;
	unsigned int slotNumber;
	double soglia;
	
	double alfa;
	double beta;
	double gamma;
	double delta;
	double epslon;
	double lambda;

/******** Main variables ******************/
	
	bool isSink;
	int nodeRingLevel;
	//~ int hopToSink;
	//~ bool nodeSynchronized;

	simtime_t constTX;
	double oh;
	unsigned int ohPktSize;
	double dq;
	double ut;
	double lifeBattery;
	unsigned int contatoreSlot;
	unsigned int contatoreFrame;
	unsigned int frameCount;		// mantiene il corretto valore del corrente "contatoreFrame" prima dell'invio con il pck EE_RL
	//~ unsigned int totalSNnodes;
	float EE;
	double ESEE;
	double idle;
	map< unsigned int, vector<neighborRecord> > framePrecEE; // mappa in cui ad ogni frameID "f" (all'interno di un FrameWindow) corrisponde un vettore di neighborRecord ( < nodeID_vicino, EE_f > ) più il nodo stesso
	vector<double> probability; // questo vettore contiene le probabilità ed ha size pari a slotNumber
	vector<unsigned int> p; // questo vettore avrà un solo elemento pari ad 1 dove il vettore probability è pari a 0
	vector<unsigned int> radioState; // questo vettore mi dice se la radio è accesa o no
	//~ vector<neighborRecord> neighborTable; // creo la tabella dei vicini (EFFECT SET)
	queue<pktTime> buffer; // coda di una struct che contiene pacchetto e timestamp di inserimento
 
/******** Utility variables ***************/

	bool firstFrame;
	
/******************************************/


 protected:
	void startup();
	void fromNetworkLayer(cPacket *, int);
	void fromRadioLayer(cPacket *, double, double);
	int handleControlCommand(cMessage * msg);
	void timerFiredCallback(int);
	void handleCarrierSenseResult(int);
	void attemptTx();
	void sendBeaconsOrData();
	
/*************************** RL METHODS ******************************************************************************************************/        
	void updateWaitingTimeQueue();
	void updateNeighborInfo(unsigned int nodeID, float EE, unsigned int frameCount); // metodo per creare ed aggiornare l'EFFECT SET 
	float energyEfficient(); //metodo per calcolare l'energy efficient
	double effectSetEnergyEfficient(); //metodo per calcolare ESEE se ho problemi di visibilita allora richiedo parametri
/*******************************************************************************************************************************************/

};

#endif				//TUNABLEMACRLMODULE
